package com.gitee.l0km.codegen.thrift;

import static com.google.common.base.Preconditions.*;
import static com.gitee.l0km.com4j.basex.reflection.generics.TypeResolution.resolveType;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.facebook.swift.codec.ThriftField;
import com.facebook.swift.codec.ThriftField.Requiredness;
import com.facebook.swift.codec.metadata.ThriftFieldMetadata;
import com.facebook.swift.codec.metadata.ThriftStructMetadata;
import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.gitee.l0km.aocache.annotations.AoWeakCacheable;
import com.gitee.l0km.codegen.annotations.CodegenDefaultvalue;
import com.gitee.l0km.codegen.annotations.CodegenInvalidValue;
import com.gitee.l0km.codegen.annotations.CodegenLength;
import com.gitee.l0km.codegen.annotations.CodegenRequired;
import com.gitee.l0km.codegen.base.AbstractSchema;
import com.gitee.l0km.codegen.base.CodeGenUtils;
import com.gitee.l0km.codegen.base.generator.GeneratorUtils;
import com.gitee.l0km.codegen.thrift.ThriftServiceDecoratorConfiguration.LanguageType;
import com.gitee.l0km.com4j.base.NameStringUtils;
import com.gitee.l0km.xthrift.base.BaseThriftUtils;
import com.gitee.l0km.xthrift.base.ThriftDecorator;
import com.gitee.l0km.xthrift.base.exception.BaseServiceException;
import com.gitee.l0km.xthrift.base.metadata.ThriftCatalogWithTransformer;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Primitives;

/**
 * 装饰类信息
 * @author guyadong
 *
 */
public class ThriftStructDecorator extends AbstractSchema implements ThriftConstants,Comparator<ThriftStructDecorator>,Comparable<ThriftStructDecorator>{
	private static final Logger logger = LoggerFactory.getLogger(ThriftStructDecorator.class);

	private final Map<String, PropertyDescriptor> fields;
	private final String decoratorPackage;
	private final String decoratorClassName;
	private final Class<?> decoratorClass;

	private final TypeHelper typeHelper = new TypeHelper(this);

	private final Map<String, CxxType> cxxFields;

	private final boolean hasOptional;
	private final boolean hasCanMove;

	private final CxxType cxxType;

	private final TraverseTypeForTryFind findString= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){
		@Override
		public boolean apply(CxxTypeMeta input) {
			return null != input && (input.isBinary() || input.isString());
		}});
	private final TraverseTypeForTryFind findBinary= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){
		@Override
		public boolean apply(CxxTypeMeta input) {
			return null != input && (input.isBinary());
		}});
	private final TraverseTypeForTryFind findMap= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){
		@Override
		public boolean apply(CxxTypeMeta input) {
			return null != input && input.isMap();
		}});
	private final TraverseTypeForTryFind findSet= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){
		@Override
		public boolean apply(CxxTypeMeta input) {
			return null != input && input.isSet();
		}});
	private final TraverseTypeForTryFind findArray= new TraverseTypeForTryFind(new Predicate<CxxTypeMeta>(){
		@Override
		public boolean apply(CxxTypeMeta input) {
			return null != input && input.isList();
		}});
	private final Predicate<PropertyDescriptor> codegenInvalidValueFilter = new Predicate<PropertyDescriptor>() {

		@Override
		public boolean apply(PropertyDescriptor input) {
			if(input != null){
				CodegenInvalidValue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenInvalidValue.class);
				if(ann != null){
					if(GeneratorUtils.isString(input.getPropertyType()) || GeneratorUtils.isBinary(input.getPropertyType())){
						// 对于String,二进制类型不判断空字符串,
						// 空字符串可以视为缺省值
						return true;
					}
					return  ann.value().length()>0 || ann.exp().length() > 0;
				}
			}
			return false;
		}
	};
	private final Predicate<PropertyDescriptor> codegenDefaultvalueFilter = new Predicate<PropertyDescriptor>() {

		@Override
		public boolean apply(PropertyDescriptor input) {
			if(input != null){
				CodegenDefaultvalue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenDefaultvalue.class);
				if(ann != null){
					if(GeneratorUtils.isString(input.getPropertyType()) || GeneratorUtils.isBinary(input.getPropertyType())){
						// 对于String,二进制类型不判断空字符串,
						// 空字符串可以视为缺省值
						return true;
					}
					return  ann.value().length()>0;
				}	
			}
			return false;
		}
	};
	private final Predicate<PropertyDescriptor> codegenLengthFilter = new Predicate<PropertyDescriptor>() {

		@Override
		public boolean apply(PropertyDescriptor input) {
			if(input != null && !input.getPropertyType().isPrimitive() && !Primitives.unwrap(input.getPropertyType()).isPrimitive()){
				CodegenLength ann = GeneratorUtils.extractFieldAnnotation(input, CodegenLength.class);
				return ann != null && (ann.value()> 0 || ann.max()> 0);
			}
			return false;
		}
	};
	private final Predicate<PropertyDescriptor> codegenRequiredFilter = new Predicate<PropertyDescriptor>() {

		@Override
		public boolean apply(PropertyDescriptor input) {
			if(input != null && !input.getPropertyType().isPrimitive() && !Primitives.unwrap(input.getPropertyType()).isPrimitive()){
				CodegenRequired ann = GeneratorUtils.extractFieldAnnotation(input, CodegenRequired.class);
				return ann != null && ann.value();
			}
			return false;
		}
	};
	private static final String FIELD_NEW_ = "_new";
	private static final String FIELD_NEW = "new";
	private static final String FIELD_MODIFIED = "modified";
	private static final String FIELD_INITIALIZED = "initialized";
	static String sql2javaBeanPkgPrefix = null;
	/** sql2java生成的JavaBean 类验证器 */
	static final Predicate<ThriftStructDecorator> SQL2JAVA_BEAN_FILTER = new Predicate<ThriftStructDecorator>(){
		private boolean checkField(ThriftStructDecorator input,String name,Class<?> type){
			try{
					PropertyDescriptor field = input.getField(name);
					return (field.getPropertyType().equals(type))
							&& field.getReadMethod() != null 
							&& field.getWriteMethod() != null;
				}catch (Exception e) {
					return false;
				}
		}
		@Override
		public boolean apply(ThriftStructDecorator input) {
			try{
				boolean m1 = checkField(input,FIELD_NEW,boolean.class) 
						&& checkField(input,FIELD_MODIFIED,int.class)
						&& checkField(input,FIELD_INITIALIZED,int.class);
				boolean m2 = checkField(input,FIELD_NEW,boolean.class) 
						&& checkField(input,FIELD_MODIFIED,int[].class)
						&& checkField(input,FIELD_INITIALIZED,int[].class);
				/** for sql2java 4.x */
				boolean m3 = checkField(input,FIELD_NEW,boolean.class) 
						&& checkField(input,FIELD_MODIFIED,String.class)
						&& checkField(input,FIELD_INITIALIZED,String.class);
				boolean m = m1 || m2 || m3;
				if(!Strings.isNullOrEmpty(ThriftStructDecorator.sql2javaBeanPkgPrefix)){
					m = m && input.getBaseClass().getPackage().getName().startsWith(ThriftStructDecorator.sql2javaBeanPkgPrefix);
				}
				return m;
			}catch (Exception e) {
				return false;
			}
		}};
	/**
	 * 对{@code baseClass}生成装饰类
	 * @param baseClass 
	 */
	public ThriftStructDecorator(Class<? > baseClass) {
		this.baseClass = checkNotNull(baseClass);
		TypeHelper.checkNotGeneric(baseClass);
		if(baseClass.isInterface()){
			throw new IllegalArgumentException("baseClass must not be interface");
		}
		if(LanguageType.CPP.equals(LanguageType.getCurrent()) 
				&& BaseThriftUtils.isException(baseClass) 
				&& !BaseThriftUtils.isThriftStruct(baseClass)){
			// 所有非thrift struct的服务异常会被生成对应的装饰类(以BaseServiceException为父类)，
			// 所以生成C++代码时要包含 BaseServiceException 的字段
			Builder<String,PropertyDescriptor> builder = ImmutableMap.builder();
			builder.putAll(typeHelper.getFields(BaseServiceException.class,Predicates.<PropertyDescriptor>alwaysTrue(),true));
			builder.putAll(typeHelper.getFields(baseClass,Predicates.<PropertyDescriptor>alwaysTrue(),true));
			fields = builder.build();
		}else{
			fields = ImmutableMap.copyOf(typeHelper.getFields(baseClass,Predicates.<PropertyDescriptor>alwaysTrue(),true));
		}
		hasOptional = Iterables.tryFind(fields.values(), new Predicate<PropertyDescriptor>(){
			@Override
			public boolean apply(PropertyDescriptor input) {
				return !input.getReadMethod().getReturnType().isPrimitive();
			}}).isPresent();

		cxxFields=LanguageType.CPP.equals(LanguageType.getCurrent()) 
				? getThriftTypes(fields) 
				: Collections.<String, CxxType>emptyMap();
		cxxType = CxxType.getThriftType(getBaseClass());
		hasCanMove = Iterables.tryFind(cxxFields.values(), new Predicate<CxxType>(){
			@Override
			public boolean apply(CxxType input) {
				return input.getStubType().isCanMove();
			}}).isPresent();
		StringBuffer buffer = new StringBuffer(baseClass.getPackage().getName());
		buffer.append( "." + BaseThriftUtils.DECORATOR_PKG_SUFFIX);
		switch(ThriftServiceDecoratorConfiguration.INSTANCE.getTaskType()){
		case CLIENT:
			buffer.append(".").append(BaseThriftUtils.CLIENT_SUFFIX);break;
		case CLIENT_THRIFTY:
			buffer.append(".").append(BaseThriftUtils.CLIENT_SUFFIX);break;
		default:
				break;
		}
		decoratorPackage = buffer.toString();
		decoratorClassName = decoratorPackage + "." + this.baseClass.getSimpleName();
		{
			Class<?> clazz = null;
			if(!isThriftStruct()){
				try {
					clazz = CodeGenUtils.forName(decoratorClassName);
				} catch (ClassNotFoundException e) {
					// DO NOTHING
				}
			}
			decoratorClass = clazz;
		}
	}
	@Override
	public boolean compile() {
		// 循环扫描检查所有的引用类型
		for(Entry<String, PropertyDescriptor> entry:fields.entrySet()){
			PropertyDescriptor descriptor = entry.getValue();
			Type returnType = resolveType(baseClass, descriptor.getReadMethod().getGenericReturnType());
			typeHelper.checkType(returnType);
			typeHelper.addReferTypes(returnType);
			if(NameStringUtils.isThriftReserved( descriptor.getName())){
				logger.warn("field name '{}' of {} is thrift IDL reserved word", descriptor.getName(),this.getBaseClass().getName());
			}
			if(NameStringUtils.isJavaReserved( descriptor.getName())){
				logger.warn("field name '{}' of {} is java reserved word", descriptor.getName(),this.getBaseClass().getName());
			}
		}
		addImportedClass(ThriftDecorator.class);
		
		return true;
	}
	public Method getGetMethod(String field){
		PropertyDescriptor descriptor = getField(field);
		return descriptor.getReadMethod();
	}
	public Method getSetMethod(String field){
		PropertyDescriptor descriptor = getField(field);
		return descriptor.getWriteMethod();
	}

	public Type getFieldType(String field){
		PropertyDescriptor descriptor = getField(field);
		return descriptor.getReadMethod().getGenericReturnType();
	}
	@AoWeakCacheable
	public PropertyDescriptor getField(String field){
		PropertyDescriptor descriptor = fields.get(field);
		if(null == descriptor){
			throw new IllegalArgumentException(String.format("INVALID field %s in %s", field,this.baseClass.getSimpleName()));
		}
		return descriptor;
	}
	/**
	 * 返回数据结构的所有字段名，如果是sql2java生成的Thrift Struct 对象，则忽略'new','initialized','modified'字段
	 * @return 字段名列表
	 */
	public List<String> getFields(){
		if(isThriftStruct()){
			ThriftStructMetadata thriftMetadata = ThriftCatalogWithTransformer.CATALOG.getThriftStructMetadata(getBaseClass());
			if(isSql2javaBean()){
				List<String> list = Lists.newLinkedList();
				// 与thrift struct中定义的字段顺序保持一致
				for(ThriftFieldMetadata field:thriftMetadata.getFields()){
					String name = field.getName();
					if(!name.equals(FIELD_NEW_) && !name.equals(FIELD_INITIALIZED) && !name.equals(FIELD_MODIFIED)){
						list.add(name);
					}
				}
				return list;
			}else{
				List<String> list = Lists.newLinkedList();
				// 与thrift struct中定义的字段顺序保持一致
				for(ThriftFieldMetadata field:thriftMetadata.getFields()){
					list.add(field.getName());
				}
				return list;
			}
		}
		ArrayList<String> list = new ArrayList<>(this.fields.keySet());
		// 字段名排序,确保输出的代码顺序稳定
		Collections.sort(list);
		return list;
	}
	/**
	 * 返回数据结构的非primitive类型所有字段名
	 * 
	 * @return 字段名列表
	 */
	public List<String> getRefFields(){
		return Lists.newArrayList(Iterables.filter(getFields(), new Predicate<String>() {

			@Override
			public boolean apply(String input) {
				return !getField(input).getPropertyType().isPrimitive();
			}
		}));
	}
	/**
	 * @return 返回枚举类型的所有对象
	 */
	public Object getEnums(){
		if(isEnum()){
			try {
				return baseClass.getMethod("values").invoke(null);
			} catch (Exception e) {
				Throwables.throwIfUnchecked(e);
				throw new RuntimeException(e);
			}
		}
		return Collections.emptyList();
	}
	public List<PropertyDescriptor> getFieldDescriptors(){
		return ImmutableList.copyOf(this.fields.values());
	}
	public String getDecoratorPackage() {
		return decoratorPackage;
	}

	public String getDecoratorClassName() {
		return decoratorClassName;
	}

	public List<ThriftStructDecorator> getDecorateTypes() {
		return typeHelper.getDecorateTypes();
	}
	public List<ThriftStructDecorator> getThriftTypes() {
		return typeHelper.getThriftTypes();
	}
	public boolean isException(){
		return Exception.class.isAssignableFrom(getBaseClass());
	}
	public boolean isThriftStruct(){
		return BaseThriftUtils.isThriftStruct(getBaseClass());
	}
	public boolean isExtThriftStruct(){
		return ThriftServiceDecoratorConfiguration.INSTANCE.getExtStructs().contains(getBaseClass());
	}
	public Class<?> getThriftClass(){
		return isThriftStruct() ? getBaseClass() : decoratorClass;
	}
	public boolean isEnum(){
		return getBaseClass().isEnum();
	}
	public boolean isBean(){
		return !isException() && !isEnum(); 
	}
	@AoCacheable
	public boolean isSql2javaBean(){
		return isBean() && SQL2JAVA_BEAN_FILTER.apply(this);
	}
	/**
	 * @since 2.3.5
	 */
	public boolean isSql2java4x(){
		if(isSql2javaBean()) {
			return  !getField(FIELD_MODIFIED).getPropertyType().isPrimitive();
		}
		return false;
	}
	public boolean hasStringConstructor(){
		return BaseThriftUtils.hasConstructor(getBaseClass(), String.class);
	}
	public String toThriftType(Type type) {
		return typeHelper.toThriftType(type);
	}

	public String toClientThriftType(Type type) {
		return typeHelper.toClientThriftType(type);
	}
	
	public String toThriftDecoratorType(Type type) {
		return typeHelper.toThriftDecoratorType(type);
	}
	public String toClientThriftyType(Type type) {
		return typeHelper.toClientThriftyType(type);
	}

	public String toThriftyDecoratorType(Type type) {
		return typeHelper.toThriftyDecoratorType(type);
	}
	
	public boolean sameWithClientThriftType(Type type) {
		return typeHelper.sameWithClientThriftType(type);
	}
	public boolean sameWithClientThriftyType(Type type) {
		return typeHelper.sameWithClientThriftyType(type);
	}
	public boolean sameWithThriftDecoratorType(Type type) {
		return typeHelper.sameWithThriftDecoratorType(type);
	}
	public boolean sameWithThriftyDecoratorType(Type type) {
		return typeHelper.sameWithThriftyDecoratorType(type);
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((baseClass == null) ? 0 : baseClass.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof ThriftStructDecorator))
			return false;
		ThriftStructDecorator other = (ThriftStructDecorator) obj;
		if (baseClass == null) {
			if (other.baseClass != null)
				return false;
		} else if (!baseClass.equals(other.baseClass))
			return false;
		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("ThriftStructDecorator [baseClass=");
		builder.append(baseClass);
		builder.append("]");
		return builder.toString();
	}
	public void removeDecorateTypesFromImports(){
		// 排除枚举类型
		Iterable<Class<?>> it = Iterables.filter(typeHelper.getTypesWithDecorator(),new Predicate<Class<?>>() {
			@Override
			public boolean apply(Class<?> input) {
				return !input.isEnum();
			}
		});
		ArrayList<Class<?>> types = Lists.newArrayList(it);
		this.removeClassFromImports(types);
	}

	@Override
	public int compare(ThriftStructDecorator o1, ThriftStructDecorator o2) {
		return o1.getBaseClass().getSimpleName().compareTo(o2.getBaseClass().getSimpleName());
	}

	@Override
	public int compareTo(ThriftStructDecorator o) {
		return getBaseClass().getSimpleName().compareTo(o.getBaseClass().getSimpleName());
	}

	private static ImmutableMap<String, CxxType> getThriftTypes(Map<String, PropertyDescriptor> fields){		
		Map<String, CxxType> m = Maps.transformValues(checkNotNull(fields,"fields is null"), 
				ThriftStructDecorator::getThriftType);
		return ImmutableMap.copyOf(m);
	}
	private static CxxType getThriftType(PropertyDescriptor descriptor) {
		if(null != descriptor) {
			Type propertyType;
			Method readMethod;
			Method writeMethod;
//			Field field = null;
			if((readMethod = descriptor.getReadMethod()) != null) {
				propertyType = readMethod.getGenericReturnType();
//				field =  FieldUtils.getField(readMethod.getDeclaringClass(), descriptor.getName(), true);
			}else if((writeMethod = descriptor.getWriteMethod()) != null) {
				propertyType = writeMethod.getGenericParameterTypes()[0];
//				field =  FieldUtils.getField(writeMethod.getDeclaringClass(), descriptor.getName(), true);
			}else {
				propertyType = descriptor.getPropertyType();
			}
			return CxxType.getThriftType(propertyType);
			/**
			 * 调用CxxType.from方法会引出更多要修改的地方，暂时关闭
			 */
//			return CxxType.from(propertyType, 
//				(null == field || field.getGenericType().equals(propertyType))? null : field.getGenericType());
		}
		return null;
	}
	public ImmutableMap<String, CxxType> getCxxFieldsAsMap(){
		return ImmutableMap.copyOf(this.cxxFields);
	}
	public CxxType getCxxField(String name){
		return cxxFields.get(checkNotNull(name,"name is null"));
	}
	/**
	 * 是否有optional字段
	 */
	public boolean isHasOptionalField(){
		return hasOptional;
	}
	
	/**
	 * 是否有需要移动的字段
	 */
	public boolean isHasCanMoveField() {
		return hasCanMove;
	}
	public CxxType getCxxType() {
		return cxxType;
	}
	
	private static class TraverseTypeForTryFind implements Predicate<CxxType>{
		private Predicate<CxxTypeMeta> finder;
		TraverseTypeForTryFind(Predicate<CxxTypeMeta> finder){
			this.finder = finder;
		}
		@Override
		public boolean apply(CxxType input) {
			if(null == input){
				return false;
			}
			CxxTypeMeta type = input.getUiType();
			if(finder.apply(type)){
				return true;
			}
			if(type.isContainer()){
				CxxTypeMeta keyType = type.getKeyType();
				CxxTypeMeta valueType = type.getValueType();
				if(null != keyType && finder.apply(keyType)){
					return true;
				}
				if(null != valueType && finder.apply(valueType)){
					return true;
				}
			}
			return false;
		}}
	public boolean isUseString(){
		return Iterables.tryFind(cxxFields.values(), findString).isPresent();
	}
	public boolean isUseBinary(){
		return Iterables.tryFind(cxxFields.values(), findBinary).isPresent();
	}
	public boolean isUseMap(){
		return Iterables.tryFind(cxxFields.values(), findMap).isPresent();
	}
	public boolean isUseSet(){
		return Iterables.tryFind(cxxFields.values(), findSet).isPresent();
	}
	public boolean isUseVector(){
		return Iterables.tryFind(cxxFields.values(), findArray).isPresent();
	}	
	public boolean isUseCodegenInvalidValue(){
		return Iterables.tryFind(fields.values(), codegenInvalidValueFilter).isPresent();
	}
	public boolean isUseCodegenDefaultvalue(){
		return Iterables.tryFind(fields.values(), codegenDefaultvalueFilter).isPresent();
	}
	public boolean isUseCodegenLength(){
		return Iterables.tryFind(fields.values(), codegenLengthFilter).isPresent();
	}
	public boolean isUseCodegenRequired(){
		return Iterables.tryFind(fields.values(), codegenRequiredFilter).isPresent();
	}
	public boolean needRenderCodegen(PropertyDescriptor input){
		return codegenInvalidValueFilter.apply(input) || 
					codegenDefaultvalueFilter.apply(input) || 
					codegenLengthFilter.apply(input) || 
					codegenRequiredFilter.apply(input);
	}
	public String renderCodegenInvalidValue(PropertyDescriptor input){
		if(codegenInvalidValueFilter.apply(input)){
			CodegenInvalidValue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenInvalidValue.class);
			if(ann.value().length() >0){
				return String.format("@CodegenInvalidValue(\"%s\")", ann.value());
			}else{
				return String.format("@CodegenInvalidValue(exp=\"%s\")", ann.exp());
			}
		}
		return null;
	}
	public String renderCodegenDefaultValue(PropertyDescriptor input){
		if(codegenDefaultvalueFilter.apply(input)){
			CodegenDefaultvalue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenDefaultvalue.class);
			return String.format("@CodegenDefaultvalue(\"%s\")", ann.value());
		}
		return null;
	}
	public String renderCodegenLength(PropertyDescriptor input){
		if(codegenLengthFilter.apply(input)){
			CodegenLength ann = GeneratorUtils.extractFieldAnnotation(input, CodegenLength.class);
			if(ann.value() >0){
				return String.format("@CodegenLength(%d,prealloc=%b)", ann.value(),ann.prealloc());
			}else{
				return String.format("@CodegenLength(max=%d,prealloc=%b)", ann.max(),ann.prealloc());
			}
		}
		return null;
	}
	public String renderCodegenRequired(PropertyDescriptor input){
		if(codegenRequiredFilter.apply(input)){
			CodegenRequired ann = GeneratorUtils.extractFieldAnnotation(input, CodegenRequired.class);
			if(ann.value()){
				return "@CodegenRequired";
			}
		}
		return null;
	}	
	public Integer lengthLimitOf(PropertyDescriptor input){
		if(codegenLengthFilter.apply(input)){
			CodegenLength ann = GeneratorUtils.extractFieldAnnotation(input, CodegenLength.class);
			int limit;
			if(ann.value() >0){
				limit = ann.value();
			}else{
				limit = ann.max();
			}
			if(String.class.equals(input.getPropertyType())){
				limit++;
			}
			return limit;
		}
		return null;
	}
	public String defaultValueOf(PropertyDescriptor input){
		if(codegenDefaultvalueFilter.apply(input)){
			CodegenDefaultvalue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenDefaultvalue.class);
			return ann.value();
		}
		return null;
	}
	public String invalidValueOf(PropertyDescriptor input){
		if(codegenInvalidValueFilter.apply(input)){
			CodegenInvalidValue ann = GeneratorUtils.extractFieldAnnotation(input, CodegenInvalidValue.class);
			if(ann.value().length() >0){
				return ann.value();
			}else{
				return ann.exp();
			}
		}
		return null;
	}
	public String initValueOf(PropertyDescriptor input){
		String initValue = invalidValueOf(input);	
		return initValue == null ? defaultValueOf(input) : initValue;
	}
	public boolean isRequired(PropertyDescriptor input){
		if(input != null){
			CodegenRequired ann = GeneratorUtils.extractFieldAnnotation(input, CodegenRequired.class);
			if(ann != null){
				return ann.value();
			}
			ThriftField thriftField=GeneratorUtils.extractFieldAnnotation(input, ThriftField.class);
			if(thriftField != null){
				return Requiredness.REQUIRED.equals(thriftField.requiredness());
			}
		}
		return false;
	}
	@AoWeakCacheable
	public boolean isRequired(String name){
		return isRequired(fields.get(name));
	}
	public boolean isNeedTransformer(){
		return typeHelper.needTransformer();
	}
}
